import { get, trim } from 'lodash';
import dayjs from 'dayjs';
import { DataTypes, Model } from 'sequelize';
import { getSequelize } from '../db/init';

export function nvl(value, default_value = 'NULL') {
  if (value === undefined || value === '' || value === null || Number.isNaN(value)) {
    return default_value;
  }

  return value;
}

export function yesorno(value) {
  return value ? 'Y' : 'N';
}

export function formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') {
  if (nvl(date, 'NULL') === 'NULL') {
    return 'NULL';
  }

  return dayjs(date).format(format);
}

export function getColumnUserLabel(attribute) {
  return get(attribute, 'label', attribute.comment);
}

export async function getForeignName(id, { model, column }) {
  if (!id) {
    return nvl(id);
  }

  const sequelize = getSequelize();
  const data = await sequelize.models[model].findOne({ where: { id }, rejectOnEmpty: new Error('引用的数据不存在') });
  // const data = await sequelize.models[model].findOne({ where: { id } });
  return get(data, nvl(column, 'name'), 'NULL');
}

/**
 * 获取数据更新记录
 * @param {*} model Sequeliize Model
 * @param {*} modelInstance Model Instance
 * @returns
 */
export async function getModelDifference(model, modelInstance) {
  const attributes = model.getAttributes();

  // console.log(attributes);
  const logs = [];
  const changed = modelInstance.changed() || []; // changed keys

  // console.log(modelInstance);
  for (const [key, attribute] of Object.entries(attributes)) {
    // console.log(keys.begin_date.type.constructor.name);
    // console.log(`${key}: `, attribute);

    if (attribute.logger && changed.indexOf(key) >= 0) {
      const oldValue = get(modelInstance, `_previousDataValues.${key}`);
      const newValue = get(modelInstance, `dataValues.${key}`);

      if (attribute.map) { // 固定值
        // console.log(attribute.map);
        // console.log(oldValue);
        // console.log(newValue);

        logs.push(`${getColumnUserLabel(attribute)}: ${nvl(attribute.map[oldValue])} -> ${nvl(attribute.map[newValue])}`);
      }
      else if (attribute.model) { // 外键
        logs.push(`${getColumnUserLabel(attribute)}: ${await getForeignName(oldValue, attribute)} -> ${await getForeignName(newValue, attribute)}`);
      }
      else {
        switch (attribute.type.constructor.name) {
          case DataTypes.DATEONLY.key:
          case DataTypes.DECIMAL.key:
          case DataTypes.INTEGER.key:
            logs.push(`${getColumnUserLabel(attribute)}: ${nvl(oldValue)} -> ${nvl(newValue)}`);
            break;
          case DataTypes.BOOLEAN.key:
            logs.push(`${getColumnUserLabel(attribute)}: ${yesorno(oldValue)} -> ${yesorno(newValue)}`);
            break;
          case DataTypes.DATE.key:
            logs.push(`${getColumnUserLabel(attribute)}: ${formatDate(oldValue)} -> ${formatDate(newValue)}`);
            break;
          default:
            logs.push(`${getColumnUserLabel(attribute)}: ${nvl(oldValue)} -> ${nvl(newValue)}`);
        }
      }
    }
  }

  return logs;
}

export function getValue(data, key, attribute) {
  let value = get(data, key, null);
  if (value && attribute.type.constructor.name === DataTypes.DATEONLY.key) {
    value = dayjs(value).format('YYYY-MM-DD');
  }
  else if (value === '') {
    value = null;
  }

  return value;
}

/**
 *
 * @param {Model} model Sequelize Model
 * @param {Model} instance Sequelize Model Instance
 * @param {Object} data 数据
 * @param {import('express').Request} req
 */
export async function updateModelData(model, instance, data, req) {
  const attributes = model.getAttributes();

  for (const [key, attribute] of Object.entries(attributes)) {
    if (attribute.editable !== false) {
      instance[key] = getValue(data, key, attribute);
    }
  }
  instance.updated_id = req.user.id;

  return getModelDifference(model, instance);
}

/**
 * 获取分页查询参数
 * @param {Object} query req.query
 * @param {Number} query.pageSize 每页行数
 * @param {Number} query.pageIndex 页码
 * @returns
 */
export function getOffsetAndLimit(query) {
  let {
    pageSize, pageIndex
  } = query;

  if (!pageSize || pageSize < 0) {
    pageSize = 50;
  }
  else if (pageSize > 2000) {
    pageSize = 2000;
  }

  pageSize = parseInt(pageSize, 10);

  if (!pageIndex) {
    pageIndex = 1;
  }

  pageIndex = parseInt(pageIndex, 10);

  let offset = 0;

  if (pageIndex > 0) {
    offset = (pageIndex - 1) * pageSize;
  }

  if (pageIndex < 0) {
    offset = undefined;
    pageSize = 20000;
  }

  return {
    limit: pageSize,
    offset,
    pageIndex
  };
}

/**
 * 获取排序规则
 * @param {String} flag 升降序标记
 * @returns
 */
export function getDirection(flag) {
  return flag === '-' ? 'DESC' : 'ASC';
}

/**
 * 获取排序方法
 * @param {Object} query req.query
 * @param {String} query.order 排序字段及规则，例如：-created_at,updated_at
 * @returns
 */
export function getOrder(query) {
  const { order } = query;
  if (order) {
    const sorts = order.split(',');
    if (sorts.length > 0) {
      const orders = [];
      sorts.forEach((col) => {
        const item = col.trim();
        if (item) {
          const columns = item.replace('-', '').split('.');

          orders.push([
            // Sequelize.literal(columns.map((e) => `\`${e}\``).join('.')),
            ...columns,
            getDirection(item.charAt(0))
          ]);
        }
      });

      return { order: orders };
    }
  }
  return { order: undefined };
}

/**
 * 获取查询字段
 * @param {Object} query req.query
 * @param {String} query.fields 查询字段
 * @returns
 */
export function getAttributes(query) {
  const { fields } = query;
  if (fields) {
    const columns = fields.split(',');
    if (columns.length > 0) {
      return { attributes: columns.map((e) => trim(e)) };
    }
  }

  return {};
}

export function getOptions(req, getFindWhere, getInclude) {
  const { query } = req;
  return {
    ...getAttributes(query),
    ...getOffsetAndLimit(query),
    ...getOrder(query),
    ...(typeof getFindWhere === 'function' ? getFindWhere(req) : {}),
    ...(typeof getInclude === 'function' ? getInclude(req) : {})
  };
}
